package yxgf.oem.oemquotemgt.mservice.service.impl;

import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import kd.bos.coderule.api.CodeRuleInfo;
import kd.bos.dataentity.OperateOption;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.metadata.IDataEntityType;
import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
import kd.bos.openapi.common.result.CustomApiResult;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.QueryServiceHelper;
import kd.bos.servicehelper.coderule.CodeRuleServiceHelper;
import kd.bos.servicehelper.operation.OperationServiceHelper;
import kd.bos.servicehelper.operation.SaveServiceHelper;
import org.springframework.stereotype.Service;
import yxgf.oem.oemquotemgt.commons.dto.*;
import yxgf.oem.oemquotemgt.commons.enums.QuoteModeEnum;
import yxgf.oem.oemquotemgt.commons.enums.QuoteTypeEnum;
import yxgf.oem.oemquotemgt.mservice.service.IContractAppointService;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @description： 合同约定服务服务
 * @version: v1.0
 * @author: Junit
 * @date: 2025/5/14
 */
@Service
public class ContractAppointServiceImpl implements IContractAppointService {
    private static final Log logger = LogFactory.getLog(ContractAppointServiceImpl.class);

    /**
     * 日志消息
     */
    public static final String LOG_PREFIX = "合同约定单定时生成定价单定时任务-";

    @Override
    public CustomApiResult<Boolean> genQuoteBill() {
        LocalDate today = LocalDate.now();
        int dayOfMonth = today.getDayOfMonth();

        /**
         * 获取已审核合同信息
         */
        QFilter qFilter1 = new QFilter("billstatus", QCP.equals, "C");
        QFilter qFilter2 = new QFilter("yxgf_start_date", QCP.less_equals, today);
        QFilter qFilter3 = new QFilter("yxgf_end_date", QCP.large_equals, today);
        QFilter qFilter4 = new QFilter("yxgf_entryentity_qperiod.yxgf_qdate", QCP.equals, dayOfMonth);
        QFilter filter = qFilter1.and(qFilter2).and(qFilter3).and(qFilter4);

        DynamicObjectCollection contractBill = QueryServiceHelper.query("yxgf_contract_bill",
                "id,billno,yxgf_advanced_days," +
                        "yxgf_start_date,yxgf_end_date," +
                        "yxgf_base_days,yxgf_quote_days,yxgf_range,yxgf_base_x," +
                        "yxgf_entryentity_qperiod.yxgf_qdate as quote_date",
                filter.toArray());

        /**
         * 获取合同信息
         */
        List<ContractBaseInfoDto> contractOriList = new ArrayList<>();
        for (DynamicObject dyn : contractBill) {
            // 基本信息
            ContractBaseInfoDto baseInfoDto = new ContractBaseInfoDto();
            String billNo = dyn.getString("billno");
            baseInfoDto.setBillNo(billNo);

            // 提前生成日
            baseInfoDto.setAdvancedDay(dyn.getInt("yxgf_advanced_days"));

            // 报价日
            List<Integer> qDays = new ArrayList<>();
            qDays.add(dyn.getInt("quote_date"));
            baseInfoDto.setQuoteDays(qDays);

            // 报价规则
            ContractQuoteRuleDto quoteRuleDto = new ContractQuoteRuleDto();
            quoteRuleDto.setBaseXDays(dyn.getInt("yxgf_base_days"));
            quoteRuleDto.setQuoteDays(dyn.getInt("yxgf_quote_days"));
            quoteRuleDto.setRange(dyn.getBigDecimal("yxgf_range"));
            quoteRuleDto.setBaseX(dyn.getBigDecimal("yxgf_base_x"));

            contractOriList.add(baseInfoDto);
            baseInfoDto.setContractQuoteRuleDto(quoteRuleDto);
        }

        // 获取报价周期
        List<ContractBaseInfoDto> list = contractOriList.stream()
                .filter(distinctByKey(ContractBaseInfoDto::getBillNo))
                .collect(Collectors.toList());

        // 查找报价日
        for (ContractBaseInfoDto tem : list) {
            // 查找相同合同
            List<ContractBaseInfoDto> sameConBill = findContractsByBillNo(contractOriList, tem.getBillNo());
            List<ContractBaseInfoDto> datesBill = findContractsByDay(sameConBill, dayOfMonth);
            if (datesBill.size() > 0) {
                // 更新合同
                updateQuoteBill(datesBill.get(0), today);
            }
        }

        return CustomApiResult.success(true);
    }


    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * 查找日期
     *
     * @param conBills
     * @param billNo
     * @return
     */
    public static List<ContractBaseInfoDto> findContractsByBillNo(List<ContractBaseInfoDto> conBills, String billNo) {
        return conBills.stream()
                .filter(order -> order.getBillNo().equals(billNo))
                .collect(Collectors.toList());
    }


    /**
     * 查找日期
     *
     * @param conBills
     * @return
     */
    public static List<ContractBaseInfoDto> findContractsByDay(List<ContractBaseInfoDto> conBills, int day) {
        return conBills.stream()
                .filter(order -> order.getQuoteDays().get(0).equals(day))
                .collect(Collectors.toList());
    }

    /**
     * 更新定价单
     */
    private void updateQuoteBill(ContractBaseInfoDto contractInfo, LocalDate today) {
        int currYear = today.getYear();
        int currMonth = today.getMonthValue();

        /**
         * 生成报价日期
         */
        if (contractInfo.getQuoteDays().size() == 0
                && contractInfo.getQuoteDays().get(0) < 0
                || contractInfo.getQuoteDays().get(0) > 31) {

            logger.info(LOG_PREFIX + "生成报价单失败，当前报价日期无效，值为:" + contractInfo.getQuoteDays().get(0));
            return;
        }
        // 生成完整报价日，确保报价日期存在
        LocalDate quoteDay;
        try {
            quoteDay = LocalDate.of(currYear, currMonth, contractInfo.getQuoteDays().get(0));
        } catch (DateTimeException e) {
            return;
        }

        /**
         * 获取提前生成定价单天数，并生成提前定价日期
         */
        int advancedDays = contractInfo.getAdvancedDay();
        if (advancedDays < 1 || advancedDays > 31) {
            logger.info(LOG_PREFIX + "生成报价单失败，获取提前生成定价单天数无效，值为:" + advancedDays);
            return;
        }
        // 生成报价日期
        LocalDate quoteDate = quoteDay.minusDays(advancedDays);

        /**
         * 判断是否是报价当天，生成定价单
         */
        if (!today.equals(quoteDate)) {   // 测试
            /**
             * 1、获取定价单信息
             */
            QFilter qFilter1 = new QFilter("billno", QCP.equals, contractInfo.getBillNo());    // 定价单编号
            QFilter qFilter2 = new QFilter("billstatus", QCP.equals, "C");                   // 已审批
            QFilter filter = qFilter1.and(qFilter2);
            DynamicObject quoteBill = QueryServiceHelper.queryOne("yxgf_recipe_pricing",
                    "id,billno," +
                            "yxgf_combofield,yxgf_bjlx," +
                            "yxgf_start_qdatetime,yxgf_qend_datetime",
                    filter.toArray());

            /**
             * 存在：则为售前报价
             * 不存在：新增--合同报价
             * 2、检查是否生成定价单，生成则不再生成，否则生成单价单
             * -是否是在合同有效日内
             * -修改报价单报价类型
             */
            if (quoteBill == null) {

                /**
                 *  3、生成单价单
                 */
                // SaveServiceHelper.save(new DynamicObject[]{quoteBill});
                genQBillEntity(contractInfo, today);
            }
        }
    }

    /**
     * 生成定价单
     *
     * @param contractInfo
     */
    private void genQBillEntity(ContractBaseInfoDto contractInfo, LocalDate today) {
        DynamicObject contractEntity = BusinessDataServiceHelper.newDynamicObject("yxgf_recipe_pricing");
        IDataEntityType dataType = contractEntity.getDataEntityType();
        String ruleName = dataType.getName();
        CodeRuleInfo codeRule = CodeRuleServiceHelper.getCodeRule(ruleName, contractEntity, null);
        String billNo = CodeRuleServiceHelper.getNumber(codeRule, contractEntity);

        /**
         * 一、基本信息
         */
        contractEntity.set("billno", billNo);
        // 单据状态暂存
        contractEntity.set("billstatus", "A");
        // 客户
        contractEntity.set("yxgf_customerfield", contractInfo.getCusId());


        /**
         * 二、报价信息
         */
        contractEntity.set("yxgf_combofield", QuoteTypeEnum.QUOTE_MODE_CON_SALE);               // 报价类型-合同报价
        contractEntity.set("yxgf_bjlx", QuoteModeEnum.QUOTE_TYPE_MAT);                          // 报价模式三种

        /**
         * 三、合同约定
         */
        contractEntity.set("yxgf_contractld", contractInfo.getBillNo());                        // 合同编号
        contractEntity.set("yxgf_start_qdatetime", contractInfo.getContractStarDay());          // 开始日期
        contractEntity.set("yxgf_qend_datetime", contractInfo.getContractEndDay());             // 结束日期
        contractEntity.set("yxgf_principal", contractInfo.getPrincipalId());                    // 负责人
        /**
         * 报价规则
         */
        ContractQuoteRuleDto conRule = contractInfo.getContractQuoteRuleDto();
        ZonedDateTime zonedDateTime = today.atStartOfDay(ZoneId.systemDefault());
        Date date = Date.from(zonedDateTime.toInstant());
        contractEntity.set("yxgf_contrat_base_date", date);                                // 合同基数计算日期
        contractEntity.set("yxgf_base_days", conRule.getBaseXDays());                       // 合同基数计算天数
        contractEntity.set("yxgf_amountfield3", conRule.getBaseX());                        // 合同基数
        contractEntity.set("yxgf_range", conRule.getRange());                               // 约定波动范围（%）


        /**
         * 四、基数计算
         */
        // DynamicObjectCollection formulaCollection = contractEntity.getDynamicObjectCollection("yxgf_subentryentity1");      // 配方
        // populatePriceDetails(formulaCollection, contractInfo.getFormulaDtoList());
        // DynamicObjectCollection hywPriceCollection = contractEntity.getDynamicObjectCollection("yxgf_subentryentity11");     // 汇易网价格明细
        // buildNutItemObject(hywPriceCollection,);

        ArrayList<DynamicObject> dynamicObjects = new ArrayList<>();
        dynamicObjects.add(contractEntity);
        DynamicObject[] dynArr = dynamicObjects.stream().toArray(DynamicObject[]::new);

        OperationServiceHelper.executeOperate("save", "yxgf_recipe_pricing", dynArr, OperateOption.create());

        // logger.info(LOG_PREFIX + "合同编号【" + contractInfo.getBillNo() + "】生成定价单成功");
    }



    private void populatePriceDetails(DynamicObjectCollection dynamicObjectCollection, List<MarketFormulaDto> formulaList) {
        IntStream.range(0, formulaList.size())
                .mapToObj(index -> buildFormulaObject(formulaList.get(index), dynamicObjectCollection.getDynamicObjectType()))
                .forEach(dynamicObjectCollection::add);
    }


    /**
     * 构建配方
     * @param forDto
     * @param type
     * @return
     */
    private DynamicObject buildFormulaObject(MarketFormulaDto forDto, DynamicObjectType type) {
        DynamicObject detail = new DynamicObject(type);
        detail.set("yxgf_basedatafield3", forDto.getMatId());
        detail.set("yxgf_use_num", forDto.getDosage());
        detail.set("yxgf_per_material", forDto.getProportion());
        return detail;
    }

    /**
     * 构建汇易网价格明细
     * @param forDto
     * @param type
     * @return
     */
    private DynamicObject buildNutItemObject(MarketFormulaDto forDto, DynamicObjectType type) {
        DynamicObject detail = new DynamicObject(type);
        detail.set("yxgf_basedatafield3", forDto.getMatId());
        detail.set("yxgf_use_num", forDto.getDosage());
        detail.set("yxgf_per_material", forDto.getProportion());
        return detail;
    }
}
